﻿; (function() {
    if (!window.$axpin) window.$axpin = {};

    /**
     * Preps the content path and loads the stylesheet for the pin plugin
     **/
    $(document).ready(function () {
        //Content URL path is relative if prototype is hosted on Axshare...
        var contentUrlPrefix = '';
        //Else if a local prototype, make content path absolute.
        if ($axure.player.settings.isAxshare === false) {
            contentUrlPrefix = window.AXSHARE_HOST_URL || 'http://share.axure.com';
        }

        $('<link>').appendTo('head').attr({
            rel: 'stylesheet',
            type: 'text/css',
            href: contentUrlPrefix + '/Content/plugins/axPin/styles/axPin.css'
        });

        // Load in resize listener lib
        $axure.utils.loadJS(contentUrlPrefix + '/Scripts/plugins/feedback/axResizeListener.js');
    });

    /**
     * Array of the possible pin colors. Just to keep track as the index corresponds to the class
     **/
     $axpin.pinColor = [
        "PURPLE",   // .pinColor_0
        "BLUE",     // .pinColor_1
        "YELLOW",   // .pinColor_2
        "RED",      // .pinColor_3
        "BLACK",    // .pinColor_4
        "GREY"      // .pinColor_5
    ];

    /**
     * Basic enum just to determine location of speech bubble tail
     **/
    $axpin.speechPosition = {
        TOP: 0,
        BOTTOM: 1,
        RIGHT_TOP: 2,
        RIGHT_BOTTOM: 3,
        LEFT_TOP: 4,
        LEFT_BOTTOM: 5
    };

    $axpin.pinZindex = 1;
    var pinCount = 1;
    var pinColorIndex = 0;

    var $controlPanel = null;
    var $targetPanel = null;
    var $parentContainer = null;
    var $clearOnClickObjs = null;

    var $targetPinToMove = null;
    var prevMousePos = {
        X: 0,
        Y: 0
    };

    $axpin.suppressClickPin = null;

    //-----------------------------------------------------------------------
    // Utility
    //-----------------------------------------------------------------------

    $axpin.axPinJsAvailable = true;

    /**
     * Remove the add pin panel and show any previously expanded pins
     **/
    $axpin.removeAll = function () {
        $('#addPinPanel').remove();

        // Find all saved pins with a certain class to be toggled to be visible
        $('.pinWasExpanded').removeClass('pinWasExpanded').click();
    }

    /**
     * Determines what kind of speech bubble to use and it's position in respect to it's pin
     **/
    $axpin.getPinBubblePositioning = function(tailPosition, isShifted) {
        var results = {
            //tailClass: "",
            pinClass: "",
            bubbleTop: 0,
            bubbleLeft: 0
        };

        switch (tailPosition) {
        //case $axpin.speechPosition.TOP:
        //    results.tailClass = "axContextSpeechBubbleTop";
        //    results.bubbleTop = 45;
        //    results.bubbleLeft = !isShifted ? 0 : 9;
        //    break;
        //case $axpin.speechPosition.BOTTOM:
        //    //results.tailClass = "axContextSpeechBubbleBottom";
        //    results.tailClass = "axContextSpeechBubbleBottomAdaptive";
        //    results.bubbleTop = -210;
        //    //results.bubbleTop = -151;
        //    results.bubbleLeft = !isShifted ? 0 : 9;
        //    break;
        case $axpin.speechPosition.RIGHT_TOP:
            //results.tailClass = "axContextSpeechBubbleRightTop";
            //results.bubbleLeft = -331;
            results.bubbleTop = !isShifted ? -9 : 0;
            results.bubbleLeft = -375;
            results.pinClass = "pinTailLeft";
            break;
        case $axpin.speechPosition.RIGHT_BOTTOM:
           // results.tailClass = "axContextSpeechBubbleRightBottom";
            //results.bubbleTop = !isShifted ? -171 : -180;
            //results.bubbleLeft = -331;
            //results.bubbleTop = !isShifted ? -156 : -169;
            results.bubbleTop = !isShifted ? -94 : -100;
            results.bubbleLeft = -375;
            results.pinClass = "pinTailLeft";
            break;
        default:
        case $axpin.speechPosition.LEFT_TOP:
            //results.tailClass = "axContextSpeechBubbleLeftTop";
            results.bubbleTop = !isShifted ? -9 : 0;
            results.bubbleLeft = 45;
            results.pinClass = "pinTailRight";
            break;
        case $axpin.speechPosition.LEFT_BOTTOM:
            //results.tailClass = "axContextSpeechBubbleLeftBottom";
            //results.bubbleTop = !isShifted ? -171 : -180;
            //results.bubbleTop = !isShifted ? -156 : -169;
            results.bubbleTop = !isShifted ? -94 : -100;
            results.bubbleLeft = 45;
            results.pinClass = "pinTailRight";
            break;
        }

        return results;
    };

    // Copied from messagecenter.js, just checks if this is a chrome file url prototype
    function isLocalChrome() {
        if ($axure.browser !== undefined && !$axure.browser.isEdge) {
            var chromeRegex = /Chrome\/([0-9]+).([0-9]+)/g;
            var chromeMatch = chromeRegex.exec(window.navigator.userAgent);
            var CHROME = Boolean(chromeMatch);
            var CHROME_5_LOCAL = chromeMatch &&
                Number(chromeMatch[1]) >= 5 &&
                location.href.indexOf('file://') >= 0;

            return CHROME_5_LOCAL == null ? false : CHROME_5_LOCAL;
        }

        return false;
    };

    // Determines if browser is Mozilla Firefox
    function isFirefox() {
        return typeof InstallTrigger !== 'undefined';
    };

    // Determines if browser is mobile
    function isMobile() {
        var userAgent = navigator.userAgent || navigator.vendor || window.opera;

        return (/window phone/i.test(userAgent)) ||
            (/android/i.test(userAgent)) ||
            (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream);
    };

    // Determines if device is iOS
    function isIOS() {
        var userAgent = navigator.userAgent;

        return userAgent.match(/iPhone/i) || userAgent.match(/iPad/i) || userAgent.match(/iPod/i);
    };

    /**
     * Get the dimensions (width and height) of the iframe content window
     * 
     * This is the full width and height of the prototype (beyond the window width and height)
     **/
    $axpin.determineIframeDimensions = function() {
        var $iframe = $($targetPanel.find('iframe')[0].contentWindow);

        return {
            width: $iframe.width(),
            height: $iframe.height()
        };
    };

    /**
     * Get the left and top of the iframe in respect to the target panel.
     * Position of this (upper left hand corner) should match the existingPinPanel position
     * 
     * This is intended to get when prototypes are center aligned or not
     **/
    $axpin.determineIframePosition = function () {
        var dimensions = $axpin.determineIframeDimensions();
        var $iframe = $($targetPanel.find('iframe')[0].contentWindow);

        var $body = $($iframe[0].document.body);
        var bodyWidth = $body.offset().left !== 0  ? $body.width() : dimensions.width;

        if(isFirefox()) {
            var left = $body[0].getBoundingClientRect().left;

            bodyWidth = left !== 0 ? $body.width() : dimensions.width;
        }

        return {
            top: 0,// Math.max(0, (dimensions.height - $($iframe[0].document.body).height()) / 2),
            left: Math.max(0, (dimensions.width - bodyWidth) / 2)
        };
    };

    /**
     * Get the scrollLeft and scrollTop of the iframe document
     **/
    $axpin.determineIframeScroll = function () {
        //var $iframe = $($targetPanel.find('iframe')[0].contentWindow.document);
        //var $iframe = $($targetPanel.find('iframe')[0].contentDocument);
        var $iframe = $($targetPanel.find('iframe')[0].contentWindow);

        return {
            scrollTop: $iframe.scrollTop(),
            scrollLeft: $iframe.scrollLeft()
        };
    };

    // Manually shifts the bubble up and down if it impedes on the bottom viewport boundary
    function shiftBubbleIfPastViewport($pin) {
        var pinPosition = $pin.position();
        var bubbleHeight = $pin.find('.pinIssueBubble, .newPinIssueBubble').height();
        var bubbleBottom = pinPosition.top + bubbleHeight;
        var viewportBottom = $axpin.determineIframeScroll().scrollTop + $(window).height();

        if (bubbleBottom > viewportBottom) {
            var topDiff = pinPosition.top;
            var botDiff = bubbleBottom - viewportBottom + 50;
            var botBoundary = bubbleHeight - ($pin.height() / 2);

            // 0 <= shift <= bubbleHeight - pinHeight
            var shift = botDiff > topDiff ? topDiff : botDiff;
            if(shift < 0) {
                shift = 0;
            } else if(shift > botBoundary) {
                shift = botBoundary;
            }

            $pin.find('.pinIssueBubble, .newPinIssueBubble').css('top', -shift + 'px');
        }
    };

    // Updates the speech bubble for a given pin's orientation and shift.
    function updateSpeechBubbleOrientationAndShift($pin) {
        if(!$pin.find('.pinIssueBubble, .newPinIssueBubble').is(':visible')) {
            return;
        }

        //  Redetermine best position for the pin bubble
        var pinPosition = $pin.position();
        var updatedPosition = $axpin.getPinBubblePositioning(determinePinBubbleOrientation(pinPosition.left, pinPosition.top), determinePinBubbleShift(pinPosition.left, pinPosition.top));

        $pin.removeClass('pinTailRight pinTailLeft').addClass(updatedPosition.pinClass);
        $pin.find('.pinIssueBubble, .newPinIssueBubble').css('top', updatedPosition.bubbleTop + 'px');
        $pin.find('.pinIssueBubble, .newPinIssueBubble').css('left', updatedPosition.bubbleLeft + 'px');

        // Shifts bubble up if bubble exceeds the bottom of the viewport
        shiftBubbleIfPastViewport($pin);
    };


    //-----------------------------------------------------------------------
    // Public Functions 
    //-----------------------------------------------------------------------

    /**
     * axpin initialization
     **/
    $axpin.init = function ($cPanel, $tPanel, $pContainer, $clearOnClickObjects) {
        // Store related objects
        $controlPanel = $cPanel;
        $targetPanel = $tPanel;
        $parentContainer = $pContainer;
        $clearOnClickObjs = $clearOnClickObjects;

        // Resize listener
        window.addEventListener('resize', function (event) {
            if(isMobile()) {
                return;
            } 

            $axpin.removeAll();
        }, false);

        // Mobile specific event handler to remove all when the device is roatated
        if(isMobile()) {
            $(window).bind('orientationchange', function(event) {
                $axpin.removeAll();
            });
        }

        // Escape key event handler
        $(document).keyup(function (e) {
            if (e.keyCode === 27) {      // esc key
                //e.stopPropagation();

                $axpin.removeAll();
            }
        });

        // Pin moving event handler
        if(!isMobile()) {
            $(document).mousemove(function(e) {
                if($targetPinToMove != null) {
                    e.preventDefault();

                    var diffX = e.clientX - prevMousePos.X;
                    var diffY = e.clientY - prevMousePos.Y;
                    prevMousePos.X = e.clientX;
                    prevMousePos.Y = e.clientY;

                    $targetPinToMove.css('left', parseInt($targetPinToMove.css('left')) + diffX + 'px');
                    $targetPinToMove.css('top', parseInt($targetPinToMove.css('top')) + diffY + 'px');

                    updateSpeechBubbleOrientationAndShift($targetPinToMove);
                }
            });
        } else {
            document.addEventListener('touchmove', function(e) {
                if($targetPinToMove != null) {
                    e.preventDefault();

                    var touch = e.touches[0] != null ? e.touches[0] : e.originalEvent.touches[0];
                    var diffX = touch.clientX - prevMousePos.X;
                    var diffY = touch.clientY - prevMousePos.Y;
                    prevMousePos.X = touch.clientX;
                    prevMousePos.Y = touch.clientY;

                    $targetPinToMove.css('left', parseInt($targetPinToMove.css('left')) + diffX + 'px');
                    $targetPinToMove.css('top', parseInt($targetPinToMove.css('top')) + diffY + 'px');

                    updateSpeechBubbleOrientationAndShift($targetPinToMove);
                }
            });
        }

        // Window fully loaded event handler
        $(window).load(function () {
            window.loaded = true;

            // Listener: Removes screenshot/preview panel if present
            $targetPanel.resize(function () {
                if ($('#addPinPanel').length) {
                    $axpin.removeAll();
                }

                // Specifically for when minimize and maximize is pressed. This shows the pin again
                //if($('#leftPanel').is(':visible') && $('a[pluginid="feedbackHost"]').hasClass('selected') && !$('#existingPinsOverlay').is(':visible')) {
                //    $axpin.showPins(true, true);
                //}
            });

            // If any other tabs are hit (or the minimize) hide all pins
            //$("a[pluginid='sitemapHost'], a[pluginid='pageNotesHost'], a[pluginid='debugHost'], #interfaceControlFrameMinimizeButton").click(function () {
            //    $axpin.showPins(false, true);
            //});

            // Hide pins if the feedbackHost button is pressed, otherwise show (might change this as we want to reload all issues)
            //$('a[pluginid="feedbackHost"]').click(function() {
            //    if ($(this).hasClass('selected')) {
            //        $axpin.showPins(true, true);
            //    } else {
            //        $axpin.showPins(false, true);
            //    }
            //});
        });

        // Load the existing pin panel
        (function iframeLoaded() {
            if (isLocalChrome()) return;

            var iframe = $targetPanel.find('iframe')[0];
            var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

            if(iframeDoc.readyState == 'complete') {
                createPinPanel(); // Need to wait til iframe is fully loaded
            } else {
                setTimeout(iframeLoaded, 100);
            }
        })();

        // Just once, set the #rightPanel to be hidden (so that pins when scrolled left get hidden) - ONLY FOR ALL CASES BUT IOS
        if(!isIOS()) {
            $targetPanel.css('overflow', 'hidden');
        }
    };

    /**
     * Removes the existing pin panel and existing pins container and rebuild it
     **/
    $axpin.prepareExistingPins = function () {
        $('#existingPinsOverlay').remove();

        createPinPanel();
    };

    /**
     * Show or hide the pin panel which dispalys all the pins
     * 
     * @param {True to show pins, false otherwise} bool 
     **/
    $axpin.showPins = function(bool, includeAddPanel, triggerPositionUpdateForActivePin) {
        if(bool) {
            $('#existingPinsOverlay').show();
            //$('#existingPinsOverlay').css("overflow","visible");
            if(includeAddPanel) {
                $('#addPinPanel').show();
            }
        } else {
            $('#existingPinsOverlay').hide();
            //$('#existingPinsOverlay').css("overflow", "hidden");

            if (includeAddPanel) {
                $('#addPinPanel').hide();
            }
        }

        // Manually trigger if any open pins (should only be one) to manually reposition if necessary
        if(triggerPositionUpdateForActivePin) {
            updateSpeechBubbleOrientationAndShift($('.expandedPin'));
        }
    }

    /**
     * Hides the temporary pin and shows the newly saved pin
     **/
    $axpin.publishPin = function (tagId, issueCode) {
        // Remove the temporary pin and expand permanent pin
        $('.pinWasExpanded').removeClass('pinWasExpanded');
        $('#newPin_' + tagId).parents('.pin').hide();
        $('#pinId_' + issueCode).click();
    };

    /**
     * Given pin issues, generates and binds the pins to the existing pin panel
     **/
    $axpin.loadPin = function (issue, profiles, isResolved, htmlGen, eventBind) {
        $('#existingPinsOverlay').append(htmlGen(issue, profiles, isResolved, determinePinBubbleOrientation(issue.x, issue.y), determinePinBubbleShift(issue.x, issue.y)));

        var $pin = $('#pinId_' + issue.code);
        eventBind($pin, determinePinBubbleOrientation, determinePinBubbleShift);

        // Bubble resize listener: Repositions the speech bubble if it exceeds the view window
        addResizeListener($pin.find('.pinIssueBubble')[0], function () {
            shiftBubbleIfPastViewport($pin);
        });

        // Binding for pin click. Performs relocation of pin bubble when shown
        $('#pinId_' + issue.code).click(function() {
            updateSpeechBubbleOrientationAndShift($(this));
        });
    };

    /**
     * Get or Set the current pin color. Will return the class to be used to match the color.
     **/
    $axpin.getOrSetCurrentPinColorClass = function (index) {
        // Set current default color
        if(index != null) {
            try {
                var colorIndex = parseInt(index);
                if(index >= 0 && index < $axpin.pinColor.length) {
                    pinColorIndex = colorIndex;
                } else {
                    pinColorIndex = 0;
                }
            } catch(e) { }
        }

        return "pinColor_" + pinColorIndex;
    };

    /**
     * Get the index (which represents the color) of the current pin color
     **/
    $axpin.getCurrentPinColorIndex = function() {
        return pinColorIndex;
    }

    /**
     * Build the class that represents the color for a given index
     **/
    $axpin.getPinColorClassFromIndex = function(index) {
        return "pinColor_" + (index >= 0 && index < $axpin.pinColor.length ? index : 0);
    };

    /**
     * Given a pincolor_ class, get the value aka the index (mainly used to be stored when we have the class name)
     **/
    $axpin.getPinColorIndexFromClass = function(pinColor) {
        return parseInt(pinColor.replace('pinColor_', ''));
    }

    /**
     * Given a jquery object, gets the classes and identifies the pinColor_ class used.
     **/
    $axpin.getPinColorFromObject = function($obj) {
        var classes = $obj.attr('class').split(' ');
        var result = null;

        $.each(classes, function(index, value) {
            if(value.indexOf('pinColor_') > -1) {
                result = value;
            }
        });

        return result;
    }

    /**
     * Get the current number that the next pin will take
     **/
    $axpin.getCurrPinNumber = function() {
        return pinCount;
    };

    /**
     * Set the current number that the next pin will take
     **/
    $axpin.setCurrPinNumber = function(count) {
        pinCount = count;

        return pinCount;
    }

    /**
     * Sets the pin that is to be relocated on the existing pin panel
     * 
     * @param leftOffset - the sidepanel widths (#leftPanel + .vsplitbar)
     **/
    $axpin.setMovingPin = function($pin, mEvent, isTouch) {
        $targetPinToMove = $pin;

        if($pin == null) {
            prevMousePos.X = 0;
            prevMousePos.Y = 0;
        } else {
            if (mEvent != null) {
                prevMousePos.X = isTouch ? mEvent.touches[0].clientX : mEvent.clientX;
                prevMousePos.Y = isTouch ? mEvent.touches[0].clientY : mEvent.clientY;
            }
        }
    }

    //-----------------------------------------------------------------------
    // Events
    //-----------------------------------------------------------------------
 
    // Scrolls the iframe to the designated left and top values
    function scrollIframe(scrollEvent, scrollLeft, scrollTop) {
        var $iframe = $($targetPanel.find('iframe')[0].contentWindow.document.body);

        $iframe.scrollTop(scrollTop);
        $iframe.scrollLeft(scrollLeft);
    };

    // Given the x and y, determines if the speech bubble needs to be shifted slightly to stay in view.
    function determinePinBubbleShift(x, y) {
        var iframeDimensions = $axpin.determineIframeDimensions();
        var iframeScroll = $axpin.determineIframeScroll();

        // Note: Border is omitted from these dimensions
        var height = $('.pinBorderOverlay').length ? $('.pinBorderOverlay').scrollTop() + $('.pinBorderOverlay').height() : iframeScroll.scrollTop + iframeDimensions.height;
        //var width = $('.pinBorderOverlay').length ? $('.pinBorderOverlay').scrollLeft() + $('.pinBorderOverlay').width() : iframeScroll.scrollLeft + iframeDimensions.width;

        var pinLength = 36;
        var halfPinLength = pinLength / 2;
        var borderWidth = $('.pinBorderOverlay').length ? parseInt($('.pinBorderOverlay').css('border-width')) : 0;

        // For adding, it works, but for regular displaying there are issues
        // Perhas offset cause in center aligned, pins outside of the iframe are negative (at least for x coord)
        // Need to be referencing the position of the pin in the viewport (aka #rightPanel)
        if($('.pinBorderOverlay').length == 0) {
            var iframePosition = $axpin.determineIframePosition();
            x = x + iframePosition.left;
            y = y + iframePosition.top;
        }

        var minX_pin = x - halfPinLength - borderWidth;
        var maxX_pin = x + halfPinLength + borderWidth;
        var minY_pin = y - halfPinLength - borderWidth;
        var maxY_pin = y + halfPinLength + borderWidth;

        //console.log(iframeScroll.scrollLeft + " " + $targetPanel.width());
        //console.log("minX: " + minX_pin + " maxX: " + maxX_pin);
        //console.log(iframeScroll.scrollTop + " " + $('.pinBorderOverlay').height());
        //console.log("minY: " + minY_pin + " maxY: " + maxY_pin);

        var result = /*minX_pin <= 0 ||*/ minY_pin <= 0 /*|| maxX_pin > width*/ || maxY_pin > height;
        return result;
    }

    // Given the x and y as well as which pin panel is present, this determines where the "tail" and position is for 
    // the speech bubble around the pin
    function determinePinBubbleOrientation(x, y) {
        var iframeDimensions = $axpin.determineIframeDimensions();
        var iframeScroll = $axpin.determineIframeScroll();
        var speechPosition;

        // Note: Border is omitted from these dimensions
        var width = $('.pinBorderOverlay').length ? $('.pinBorderOverlay').scrollLeft() + $('.pinBorderOverlay').width() : iframeScroll.scrollLeft + iframeDimensions.width;
        var height = $('.pinBorderOverlay').length ? $('.pinBorderOverlay').scrollTop() + $('.pinBorderOverlay').height() : iframeScroll.scrollTop + iframeDimensions.height;

        // Bubble is 300 x 180, 10px padding (all around), 1px border (all around)
        //var bubbleWidth = 322;
        var bubbleWidth = 350;
        //var bubbleHeight = 202;
        var bubbleHeight = 225;

        var pinWidth = 36;

        // 18px is the shortest distance from the edge to the tip of the speech bubble tail
        var maxX_bubble = x + bubbleWidth + pinWidth + 10;
        var maxY_bubble = y + bubbleHeight + pinWidth + 10;    

        var isRight = maxX_bubble > width;
        var isTop = maxY_bubble <= height;

        if(isTop && isRight) {
            speechPosition = $axpin.speechPosition.RIGHT_TOP;
        } else if(!isTop && isRight) {
            speechPosition = $axpin.speechPosition.RIGHT_BOTTOM;
        } else if(!isTop && !isRight) {
            speechPosition = $axpin.speechPosition.LEFT_BOTTOM;
        } else {
            speechPosition = $axpin.speechPosition.LEFT_TOP;
        }

        return speechPosition;
    };

    // Repositions the existing pin panel to match the iframe's scroll position
    function repositionExistingPinPanel() {
        // Theres an issue where when the iframe isn't loaded up yet, this call fails
        (function repositionWhenReady() {
            if($($targetPanel.find('iframe')[0].contentWindow.document.body).length === 0) {
                setTimeout(repositionWhenReady, 50);
            } else {
                var position = $axpin.determineIframePosition();
                var scroll = $axpin.determineIframeScroll();

                $('#existingPinsOverlay').css('left', position.left - scroll.scrollLeft);
                $('#existingPinsOverlay').css('top', -scroll.scrollTop);
            }
        })();
    }

    // Performs the actual html and event binding for the new temporary pin. Firgures out the position it will sit due to borders.
    function drawPin(x, y, color, count, htmlGen, eventBind) {
        var shiftedX = x - 27;      // (36 / 2) + 9
        var shiftedY = y - 27;

        // Remove any existing pins that aren't permanent (one one working pin at a time)
        $('.pinTargetOverlay').find('.pin').remove();

        var orientation = determinePinBubbleOrientation(shiftedX, shiftedY);
        var shift = determinePinBubbleShift(shiftedX, shiftedY);
        var positioning = $axpin.getPinBubblePositioning(orientation, shift);
        var newPin = [
            '<div id="tempPinId_', count, '" class="pin expandedPin pinColor_', color, ' ',positioning.pinClass, '" style="left: ', shiftedX, 'px; top: ', shiftedY, 'px;">',
                (parseInt(count) > 99 ? '+' : count),
                htmlGen(orientation, shift, color, count),
            '</div>'
        ].join("");

        $('.pinTargetOverlay').append(newPin);

        var $pin = $('.pinTargetOverlay').find('#tempPinId_' + count);
        shiftBubbleIfPastViewport($pin);

        eventBind($pin.find('.newPinIssueContainer'), x, y, color, count);
        $pin.click(function() {
            updateSpeechBubbleOrientationAndShift($(this));
        });

        // Listens to when the window resizes itself (doesn't work when adding screenshots!)
        addResizeListener($pin.find('.axPinContextSpeechBubble')[0], function () {
            shiftBubbleIfPastViewport($pin);
        });
    };

    // Appends the new pin issue on the temporary pin panel. This determines where the pin will sit as well as gen the bubble and events
    function addNewPinComment(clickEvent, scrollLeft, scrollTop, htmlGen, eventBind) {
        var leftOffset = parseInt($targetPanel.css('left'));
        var x = clickEvent.pageX - leftOffset + scrollLeft;
        var y = clickEvent.pageY + scrollTop;

        drawPin(x, y, $axpin.getCurrentPinColorIndex(), pinCount, htmlGen, eventBind);
    };


    //-----------------------------------------------------------------------
    // HTML Related Functionality
    //-----------------------------------------------------------------------

    // Binds events for when the pin panel is present. mainly resizing and scrolling events.
    function bindPinPanelEvents() {
        var $iframe = $($targetPanel.find('iframe')[0].contentWindow.document);

        // TODO: Bind the zoom events

        // Resize event - resize with pin panel window
        //$targetPanel.resize(function(event) {
        $(window).resize(function() {
            repositionExistingPinPanel();
        });

        // Scroll event - scroll pin panel so that pins match up to the iframe position
        $iframe.scroll(function () {
            repositionExistingPinPanel();
        });
    };

    // Creates the panel and overlay that will display saved pins
    function createPinPanel() {
        if (!$('#existingPinsOverlay').length) {
            var existingPinsOverlay = document.createElement('div');
            existingPinsOverlay.setAttribute('id', 'existingPinsOverlay');
            
            $targetPanel.prepend(existingPinsOverlay);
            repositionExistingPinPanel();
          
            $(existingPinsOverlay).append('&nbsp;');

            bindPinPanelEvents();
        }
    };

    // Adds the overlay over the control panel which disables any events on it. 
    function addPinControlOverlay($addPinPanel, $anchor) {
        if ($('#addPinPanel').length && !$('.pinControlOverlay').length) {
            // controlPanel dimensions
            var x = parseInt($controlPanel.css('left'));
            var width = parseInt($controlPanel.css('width'));
            var height = parseInt($controlPanel.css('height'));

            // Build pin control overlay
            var pinControlOverlay = document.createElement('div');
            pinControlOverlay.setAttribute('class', 'pinControlOverlay');
            pinControlOverlay.style.left = x.toString() + 'px';
            pinControlOverlay.style.width = width.toString() + 'px';
            pinControlOverlay.style.height = height.toString() + 'px';

            var anchorPos = ($anchor[0]).getBoundingClientRect();

            var pinControlCloseBtn = [
                '<div id="feedbackNewIssuePinCloseBtn" class="feedbackPinBtn" style="left: ', anchorPos.left, 'px; top: ', anchorPos.top, 'px; width: ', $anchor.width(), 'px;">',
                '   <span>EXIT COMMENT ON SCREEN</span>',
                '</div>'
            ].join("");

            //if (y != null) {
            //    previewPanel.style.top = y.toString() + 'px';
            //}

            $addPinPanel.append(pinControlOverlay);
            $(pinControlOverlay).append(pinControlCloseBtn);
        }
    };

    // Adds the overlay where users will be adding pins
    function addPinTargetOverlay ($addPinPanel) {
        if ($('#addPinPanel').length && !$('.pinTargetOverlay').length) {
            var $iframe = $targetPanel.find('iframe');
            var iframeScrollTop = $($iframe[0].contentWindow.document.body).scrollTop();
            var iframeScrollLeft = $($iframe[0].contentWindow.document.body).scrollLeft();

            // 
            var x = parseInt($targetPanel.css('left'));
            var width = parseInt($targetPanel.css('width'));
            var height = parseInt($targetPanel.css('height'));

            var pinBorderOverlay = document.createElement('div');
            pinBorderOverlay.setAttribute('class', 'pinBorderOverlay');
            pinBorderOverlay.style.left = x.toString() + 'px';
            pinBorderOverlay.style.width = (width - 18).toString() + 'px';     // subtract 18 due to border, 9 each for left and right side
            pinBorderOverlay.style.height = (height - 18).toString() + 'px';   // subtract 18 due to border, 9 each for left and right side

            var pinTargetOverlay = document.createElement('div');
            pinTargetOverlay.setAttribute('class', 'pinTargetOverlay');

            var closeIcon = [
                '<div class="clearIcon" style=""></div>'
            ].join("");

            $addPinPanel.append(pinBorderOverlay);

            $(pinBorderOverlay).append(pinTargetOverlay);
            $(pinBorderOverlay).append(closeIcon);
            $(pinTargetOverlay).append('&nbsp;');

            $(pinBorderOverlay).scrollTop(iframeScrollTop);
            $(pinBorderOverlay).scrollLeft(iframeScrollLeft);
        }
    };

    // Binds events for when the add pin panels and overlays are present
    function bindAddPinPanelEvents(htmlGenerator, eventBind) {
        $('#feedbackNewIssuePinCloseBtn, .clearIcon').click(function (event) {
            $axpin.removeAll();
        });

        $('.pinTargetOverlay').click(function (event) {
            if ($('.pinTargetOverlay').is(event.target)) {
                addNewPinComment(event, $(this).parent().scrollLeft(), $(this).parent().scrollTop(), htmlGenerator, eventBind);
            }
        });

        $('.pinBorderOverlay').scroll(function(event) {
            scrollIframe(event, $(this).scrollLeft(), $(this).scrollTop());
        });
    };

    /**
     * Creates the panel and overlays that will allow adding new pins
     * 
     * @param {button anchor to close the add pin mode} $anchor
     **/
    $axpin.createAddPinPanel = function ($anchor, htmlGenerator, eventBind) {
        //if(isMobile()) {
        //    $addPinAnchor = $anchor;
        //    $addPinHtml = htmlGenerator;
        //    $addPinEvents = eventBind;

        //    mobileAddPinMode = true;
        //}

        if (!$('#addPinPanel').length) {
            // targetPanel dimensions
            var zIndex = parseInt($targetPanel.css('z-index'));

            var pinPanel = document.createElement('div');
            pinPanel.setAttribute('id', 'addPinPanel');
            pinPanel.style.zIndex = zIndex + 2;

            $parentContainer.append(pinPanel);

            addPinControlOverlay($('#addPinPanel'), $anchor);
            addPinTargetOverlay($('#addPinPanel'));
            bindAddPinPanelEvents(htmlGenerator, eventBind);

            // Add class to know which saved pins were originally expanded
            // Toggle all saved pins to be hidden
            $('.savedPin .pinIssueBubble:visible').parent().addClass('pinWasExpanded').click();
        }
    };
})();